<template>
  <div class="app-container h-flex">
    <div class="tree-box app-container__left">
      <div class="type-title">角色</div>
      <el-tree
        ref="tree"
        :data="optionsApp"
        node-key="id"
        icon-class="el-icon-arrow-right"
        :expand-on-click-node="false"
        default-expand-all
        :props="defaultDeptProps"
        @node-click="chooseRole" />
    </div>
    <div ref="tree_box_right" class="h-flex-elastic v-flex overflow-hidden app-container__right">
      <div>
        <div class="filter-container">
          <el-form ref="form" class="query-condition" @submit.native.prevent>
            <el-form-item style="float:right">
              <el-checkbox v-model="menuAll">全选</el-checkbox>
            </el-form-item>
            <el-form-item>
              <el-button
                size="mini"
                type="primary"
                icon="el-icon-check"
                @click="saveOrUpdate">保存</el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
      <div ref="main" class="v-flex-elastic">
        <el-table
          v-if="height>0"
          ref="multipleTable"
          v-loading="listLoading"
          :data="tableData"
          border
          row-key="id"
          :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
          :height="height"
          tooltip-effect="dark"
          style="width: 100%">
          <el-table-column label="序号" align="center" type="index" width="50" />
          <el-table-column prop="menuName" label="菜单名称" width="200" />
          <el-table-column label="启用" align="center" width="100">
            <template slot-scope="{$index}">
              <el-checkbox
                v-model="menuList[$index].isAll"
                :indeterminate="menuList[$index].indeterminate"
                @change="checkRow(menuList, $index)">启用</el-checkbox>
            </template>
          </el-table-column>
          <el-table-column label="按钮">
            <template slot-scope="{row, $index}">
              <el-checkbox-group
                v-if="row.actions && row.actions.length>0 && !row.children.length"
                v-model="menuList[$index].actions"
                class="unset"
                @change="checkItem(menuList, $index)">
                <el-checkbox
                  v-for="item in row.actions"
                  :key="item.value"
                  :label="item.value">{{ item.label }}</el-checkbox>
              </el-checkbox-group>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>
  </div>
</template>

<script>
import { getListByApp } from '@/api/dsc/system/role'
import { getList as getListTableTree } from '@/api/dsc/system/menu'
import { getList, saveOrUpdate } from '@/api/dsc/system/role-auth'
import { tableMixin } from '@/utils/public'
export default {
  name: 'DscRoleAuth',
  mixins: [tableMixin],
  data() {
    return {
      defaultDeptProps: {
        children: 'children',
        label: 'label'
      },
      currentApp: {}, // 当前应用
      optionsApp: [],
      height: 0, // table高度
      tableData: [], // 表格数据
      roleInfo: {},
      listLoading: false,
      menuList: [],
      maxLevel: 0 // 列表树最大层级
    }
  },
  computed: {
    menuAll: {
      get() {
        const topLevel = this.menuList.filter(item => !item.parentId)
        return topLevel.length ? !topLevel.some(item => !item.isAll) : false
      },
      set(val) {
        for (const item of this.menuList) {
          item.isAll = val
          if (val) item.indeterminate = false
          item.actions = val ? item.actionList.map(child => child.value) : []
        }
      }
    }
  },
  created() {
    // 查询所属角色
    getListByApp({}).then(response => {
      this.optionsApp = response.data
      // 控制第一级平台、第二级应用不可选择
      for (const i of this.optionsApp) {
        i['disabled'] = true
        for (const j of i.children) {
          j['disabled'] = true
          if (j.children.length && !this.currentApp.id) {
            this.chooseRole(j.children[0])
          }
        }
      }
    })
  },
  methods: {
    // 选择角色
    async chooseRole(data) {
      if (this.listLoading || data.disabled || (this.roleInfo.id && this.roleInfo.id === data.id)) { return }
      this.roleInfo = data
      this.$nextTick(_ => {
        // 为了初始化高亮
        this.$refs.tree.setCurrentKey(this.roleInfo.id)
      })
      const currentApp = this.getCurrentApp()
      if (!this.currentApp.id || this.currentApp.id !== currentApp.id) {
        this.currentApp = currentApp
        await this.getAllMenu()
      }
      this.getList()
    },
    getCurrentApp() {
      let currentApp
      for (const i of this.optionsApp) {
        if (currentApp) break
        for (const j of i.children) {
          if (currentApp) break
          if (j.children.some(item => item.id === this.roleInfo.id)) {
            currentApp = j
          }
        }
      }
      return currentApp
    },
    getAllMenu() {
      this.tableData = []
      this.maxLevel = 0
      this.menuList = []
      this.listLoading = true
      return getListTableTree({ appId: this.currentApp.id })
        .then(response => {
          this.tableData = response.data
          // 递归调用得到一个普通数组列表，为了和返回的权限做对比回显
          const self = this
          function recursive(data, level) {
            self.maxLevel = Math.max(level, self.maxLevel)
            for (const item of data) {
              const menuListItem = {
                level: level,
                menuName: item.menuName,
                menuId: item.id,
                parentId: item.parentId,
                actionList: item.actions || [], // 菜单所有的按钮
                actions: [], // 菜单选择的按钮权限
                isShow: false,
                isAll: false,
                indeterminate: false
              }
              self.menuList.push(menuListItem)
              if (item.children && item.children.length) {
                recursive(item.children, level + 1)
              }
            }
          }
          recursive(this.tableData, 1)
        })
        .catch(_ => {})
    },
    // 查询权限列表
    getList() {
      this.listLoading = true
      getList({ roleId: this.roleInfo.id })
        .then(response => {
          this.menuList.forEach(item => {
            item.actions = []
            item.isShow = false
            item.isAll = false
            item.indeterminate = false
          })
          // 从树的最后层级判断选择情况
          for (let i = this.maxLevel; i > 0; i--) {
            // 取得当前层级的数据
            const levelList = this.menuList.filter(item => item.level === i)
            levelList.forEach(item => {
              const sameItem = response.data.filter(child => item.menuId === child.menuId)[0]
              if (sameItem) {
                item.actions = sameItem.actions
                item.isShow = !!sameItem.isShow
              }
              if (i === this.maxLevel) {
                item.isAll = item.actionList.length
                  ? item.actionList.length === item.actions.length
                  : item.isShow
                item.indeterminate = !!item.actions.length && !item.isAll
              } else {
                //   非最后层级根据子级判断
                const children = this.menuList.filter(child => child.parentId === item.menuId)
                if (children.length) {
                  item.isAll = !children.some(child => !child.isAll)
                  item.indeterminate = children.some(child => (child.isAll || child.indeterminate)) && !item.isAll
                } else {
                  item.isAll = item.actionList.length
                    ? item.actionList.length === item.actions.length
                    : item.isShow
                  item.indeterminate = !!item.actions.length && !item.isAll
                }
              }
            })
          }
          this.listLoading = false
        })
        .catch(_ => {
          this.listLoading = false
        })
    },
    // 全选一行
    checkRow(menuList, index) {
      const rowData = menuList[index]
      menuList[index].actions = rowData.isAll
        ? rowData.actionList.map(item => item.value)
        : []
      rowData.indeterminate = false
      this.checkStatus(menuList, index)
    },
    // 选择按钮权限
    checkItem(menuList, index) {
      const rowData = menuList[index]
      rowData.isAll = rowData.actions.length === rowData.actionList.length
      rowData.indeterminate = !!rowData.actions.length && !rowData.isAll
      this.checkStatus(menuList, index)
    },
    // 设置当前选择行的父子级的选择情况
    checkStatus(menuList, index) {
      const rowData = menuList[index]
      let parentId = rowData.parentId
      const menuId = rowData.menuId
      // 父级
      while (parentId) {
        const parent = menuList.filter(item => item.menuId === parentId)[0]
        const children = menuList.filter(item => item.parentId === parentId)
        parent.isAll = !children.some(item => !item.isAll)
        parent.indeterminate =
          (children.some(item => item.isAll) && !parent.isAll) ||
          children.some(item => item.indeterminate)
        parentId = parent.parentId
      }
      // 子级
      const children = menuList.filter(item => item.parentId === menuId)
      while (children[0]) {
        children[0].isAll = rowData.isAll
        const hasChildren = menuList.filter(
          item => item.parentId === children[0].menuId
        )
        if (hasChildren.length) {
          children.push(...hasChildren)
          children[0].indeterminate = false
        } else {
          children[0].actions = children[0].isAll
            ? children[0].actionList.map(item => item.value)
            : []
          children[0].indeterminate =
            !!children[0].actions.length && !rowData.isAll
        }
        children.shift()
      }
    },
    // 保存权限
    saveOrUpdate() {
      if (!this.roleInfo.id) {
        this.notifiyError('请先选择角色')
        return
      }
      if (this.listLoading) return
      this.listLoading = true
      const arr = Object.assign([], this.menuList)
      const permissions = []
      for (const i of arr) {
        permissions.push({
          actions: i.actions,
          isShow: i.isAll || i.indeterminate ? 1 : 0,
          menuId: i.menuId,
          id: null
        })
      }
      const param = {
        roleId: this.roleInfo.id,
        permissionList: permissions
      }
      saveOrUpdate(param).then(response => {
        this.notifiySuccess('保存成功!')
        this.listLoading = false
      }).catch(() => {
        this.listLoading = false
      })
    }
  }
}
</script>
<style lang="scss">
.unset {
  display: unset;
}
.el-dialog {
  .el-table__body-wrapper {
    overflow: hidden;
  }
}
</style>
